#include "buffer.h"

BufferQueue::BufferQueue(int max_queue_length, string queue_id) :
	m_max_queue_length(max_queue_length+1),
	m_queue_id(queue_id),
	m_buffer(NULL),
	head(0),
	tail(0)
{
}

BufferQueue::~BufferQueue() {
	delete m_buffer;
	m_buffer = NULL;
}

CODEC_ERROR BufferQueue::initQueue() {
	m_buffer = new unsigned char[m_max_queue_length];

	if(!m_buffer) {
		//log here
		return CODEC_ERROR_NO_MEM_AVALIABLE;
	}

	return CODEC_OK;
}

CODEC_ERROR BufferQueue::queueLength(int& length) {

	if(head <= tail) {
		length = tail - head;
	}
	else {
		length = m_max_queue_length - head + tail;
	}

	return CODEC_OK;
}

CODEC_ERROR BufferQueue::enQueue(unsigned char* buffer, int length) {

	int cur_queue_length = 0;
	queueLength(cur_queue_length);

	if(cur_queue_length + length >= m_max_queue_length) {
		//log here
		return CODEC_ERROR_QUEUE_FULL;
	}

	if(head >= tail) {
		memcpy(m_buffer + tail, buffer, length);
	}
	else {
		int first_seg_length = m_max_queue_length - tail;
		if(first_seg_length >= length) {
			memcpy(m_buffer + tail, buffer, length);
		}
		else {
			int second_seg_length = length - first_seg_length;
			memcpy(m_buffer + tail, buffer, first_seg_length);
			memcpy(m_buffer, buffer+first_seg_length, second_seg_length);
		}
	}

	tail = (tail + length) % m_max_queue_length;

	return CODEC_OK;
}

//CODEC_ERROR BufferQueue::enQueueOverlap(unsigned char* buffer, int length) {
//
//	int cur_queue_length = 0;
//	queueLength(cur_queue_length);
//
//	if(length >= m_max_queue_length) {
//		//log here
//		return CODEC_ERROR_QUEUE_FULL;
//	}
//
//	int first_seg_length = m_max_queue_length - tail;
//
//	if(first_seg_length < length) {
//		int second_seg_length = length - first_seg_length;
//		memcpy(m_buffer + tail, buffer, first_seg_length);
//		memcpy(m_buffer, buffer+first_seg_length, second_seg_length);
//	}
//	else {
//		memcpy(m_buffer + tail, buffer, length);
//	}
//
//	return CODEC_OK;
//}

CODEC_ERROR BufferQueue::rewind(int offset) {

	head = (head + offset) % m_max_queue_length;
	return CODEC_OK;
}

CODEC_ERROR BufferQueue::deQueue(unsigned char* buffer, int length) {

	int cur_queue_length = 0;
	queueLength(cur_queue_length);

	if(cur_queue_length <= length) {
		//log here
		return CODEC_ERROR_QUEUE_EMPTY;
	}

	if(head <= tail) {
		memcpy(buffer, m_buffer + head, length);
	}
	else {
		int first_seg_length = m_max_queue_length - head;
		if(first_seg_length >= length) {
			memcpy(buffer, m_buffer + head, length);
		}
		else {
			int second_seg_length = length - first_seg_length;
			memcpy(buffer, m_buffer + head, first_seg_length);
			memcpy(buffer+first_seg_length, m_buffer, second_seg_length);
		}
	}

	head = (head + length) % m_max_queue_length;

	return CODEC_OK;
}

unsigned char* BufferQueue::getData() {
	return m_buffer + head;
}

int BufferQueue::getHead() {
	return head;
}

int BufferQueue::getTail() {
	return tail;
}
